package utils;

import java.math.BigDecimal;

public class SnCodeUtil {
    /**
     * 0-9 a-p x 位, 可以理解为 x 进制
     */
    private static SnCodeUtil instance;
 
    public static SnCodeUtil getInstance() {
        if (instance == null) {
            instance = new SnCodeUtil();
        }
        return instance;
    }

    public static void main(String[] args) {
        System.out.println("原始数据："+1376565597554343936l +
                "   加密后数据"+ SnCodeUtil.getInstance().Int2Sn(1376565597554343936l) +
                "   解密后数据"+ SnCodeUtil.getInstance().Sn2Int(SnCodeUtil.getInstance().Int2Sn(1376565597554343936l)));

    }


    private char[] MySerials;
 
    private SnCodeUtil() {
        MySerials = new char[]{
                '2', '3', '4', '5', '6', '7', '8', '9',
                'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
                'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p','r','s','t','u','v','w','x','y','z',
                'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
                'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P','R','S','T','U','V','W','X','Y','Z'
        };
    }
 
    /**
     * 获取当前 x 进制 数的索引
     * 即 一个字符时: x 进制的 十进制表示
     *
     * @param c
     * @return
     */
    private int GetMySnIndex(String c) {
        int index = 0;
        for (int i = 0; i < MySerials.length; i++) {
            String s = String.valueOf(MySerials[i]);
            if (c.equals(s)) {
                index = i;
                break;
            }
        }
        return index;
    }
 
 
    /**
     * 目的: 获取 x 进制的下一位 Sn
     * 步骤:
     * 1. 获取x进制数,转成10进制,
     * 2.10进制数+1
     * 3.再转成x进制
     * 因为x不可直接计算
     *
     * @param start
     * @return
     */
    public String next(String start) {
        long i = Sn2Int(start);
        return Int2Sn(i + 1);
    }
 
    /**
     * Sn to Int
     * x 进制数转成 10 进制
     *
     * @param start
     * @return
     */
    public long Sn2Int(String start) {
        BigDecimal result = BigDecimal.valueOf(0);
        //将字符串拆成 char 数组
        char[] chars = start.toCharArray();
        //循环数组,对每一个字符运算转成x进制, 然后相加得到10进制数
        for (int i = 0; i < chars.length; i++) {
            /**
             * 1.个位直接取x的索引,即x进制的数字
             *  十位取x进制的数字后要 乘以x (类似10位的数字"1"表示10,"2"表示 20,即 数字*10的一次方)
             *  百位取x进制的数字后要乘以x 的二次方(类似百位的数字"1"表示100,"2"表示200,即数字*10的二次方)
             *  所以:  x进制的数字为 n*x* 的(n的位数-1 次方)
             */
            /**
             *   获取位数(十位,百位,千位): 正向循环 第一位实际是数字的最高位
             *   减1 : 取 位数-1 次方
             */
 
            int pow = chars.length - i - 1;
 
            /**
             * 索引即 x进制单字符转10进制后的数值
             */
            int index = GetMySnIndex(String.valueOf(chars[i]));
            /**
             *数字 n * x的(位数减1次方)
             * 相加 得到所有位数的10进制数字
             */
            //System.out.println("值："+String.valueOf(chars[i])+"索引："+index+"每个位置上的值："+"----"+BigDecimal.valueOf(MySerials.length).pow(pow).multiply(BigDecimal.valueOf(index)));

            result = result.add(BigDecimal.valueOf(MySerials.length).pow(pow).multiply(BigDecimal.valueOf(index)));
            //result += index * Math.pow(MySerials.length, Double.valueOf(pow));

        }
        return result.longValue();
    }
 
    /**
     * 通过取模获取 x 进制的余数 index
     * 反向加到加入字符串中
     *
     * @param n
     * @return
     */
    public String Int2Sn(long n) {
        String s = "";
        //商==0 代表循环完毕
        // 小余x的数字 除以x 等于0
        if (n == 0) {
            s = "0";
        }
        //int pow = 0;
        while (n != 0) {
            //对x取余
            BigDecimal[] results = BigDecimal.valueOf(n).divideAndRemainder(BigDecimal.valueOf(MySerials.length));
            //int i = (int) (n % MySerials.length);
            int i = results[1].intValue();
            n = results[0].longValue();
            //获取x进制数值
            char c = MySerials[i];
            //反向加入字符串中
            s = c + s;
            //.out.println("拼接："+s);
            //System.out.println("值："+String.valueOf(c)+"索引："+i+"每个位置上的值："+"----"+BigDecimal.valueOf(MySerials.length).pow(pow).multiply(BigDecimal.valueOf(i)));
           // pow++;
            //求商
            //n = n / MySerials.length;
        }

        //返回结果
        return s;
    }
}